package security

import (
	"crypto/rand"
	"crypto/rsa"
	"crypto/x509"
	"embed"
	"encoding/pem"
	"github.com/go-emix/utils"
	"os"
)

// 生成RSA私钥和公钥
// bits 证书位数，示例2048 saveDir 保存目录
func GenerateRSAKey(bits int, saveDir string) error {
	if !utils.FileIsExist(saveDir) {
		_ = os.MkdirAll(saveDir, os.ModePerm)
	}
	privateKey, err := rsa.GenerateKey(rand.Reader, bits)
	if err != nil {
		return err
	}
	x509PrivateKey := x509.MarshalPKCS1PrivateKey(privateKey)
	privateFile, err := os.Create(saveDir + "/private.pem")
	if err != nil {
		return err
	}
	defer func() {
		_ = privateFile.Close()
	}()
	privateBlock := pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509PrivateKey}
	err = pem.Encode(privateFile, &privateBlock)
	if err != nil {
		return err
	}
	publicKey := privateKey.PublicKey
	X509PublicKey, err := x509.MarshalPKIXPublicKey(&publicKey)
	if err != nil {
		return err
	}
	publicFile, err := os.Create(saveDir + "/public.pem")
	if err != nil {
		return err
	}
	defer func() {
		_ = publicFile.Close()
	}()
	publicBlock := pem.Block{Type: "RSA PUBLIC KEY", Bytes: X509PublicKey}
	err = pem.Encode(publicFile, &publicBlock)
	return err
}

// RSA加密
// content 要加密的内容 pubKey 公钥
func RSAEncrypt(content string, pubKey []byte) (string, error) {
	block, _ := pem.Decode(pubKey)
	publicKeyInterface, err := x509.ParsePKIXPublicKey(block.Bytes)
	if err != nil {
		return "", err
	}
	publicKey := publicKeyInterface.(*rsa.PublicKey)
	cipherText, err := rsa.EncryptPKCS1v15(rand.Reader, publicKey, []byte(content))
	if err != nil {
		return "", err
	}
	return string(cipherText), nil
}

// RSA解密
// cipherText 密文 privateKey 私钥
func RSADecrypt(cipherText string, privateKey []byte) (string, error) {
	block, _ := pem.Decode(privateKey)
	priKey, err := x509.ParsePKCS1PrivateKey(block.Bytes)
	if err != nil {
		return "", err
	}
	plainText, err := rsa.DecryptPKCS1v15(rand.Reader, priKey, []byte(cipherText))
	if err != nil {
		return "", nil
	}
	return string(plainText), nil
}

// 相对于当前go文件来计算路径
//go:embed pem
var efs embed.FS

var PriKey []byte
var PubKey []byte

func init() {
	var err error
	PriKey, err = efs.ReadFile("pem/private.pem")
	utils.PanicError(err)
	PubKey, err = efs.ReadFile("pem/public.pem")
	utils.PanicError(err)
}
